﻿package fab.geom
{
	import fab.geom.Line;
	import flash.geom.Point;

	public class LineUtil 
	{
	
		/**
		 * Returns a Line reference defines with the two vectors in argument. 
		 * This line is a line equation as two properties (a,b) such that (y = a*x + b) for any x or a unique c property such that (x = c) for all y.
		 * The function takes two points as parameter, p0 and p1 containing two properties x and y.
		 * @return a line equation as two properties (a,b) such that (y = a*x + b) for any x or a unique c property such that (x = c) for all y.
	 	 */
		public static function getLine( p1:Point, p2:Point ):Line 
		{
			var x0:Number = p1.x;
			var y0:Number = p1.y;
			var x1:Number = p2.x;
			var y1:Number = p2.y;
			var l:Line = new Line() ;
			if (x0 == x1) 
			{
				if (y0 == y1)
				{
					l = null ;
				}
				else 
				{
					l.c = x0 ; // Otherwise, the line is a vertical line
				}
			}
			else 
			{
				l.a = (y0 - y1) / (x0 - x1) ;
				l.b = y0 - (l.a * x0) ;
			}
			return l ;
		}
	
		/**
	 	 * Returns a point (x,y) that is the intersection of two lines.
	 	 * A line is defined either by a and b parameters such that (y = a*x + b) for any x or 
	 	 * a single parameter c such that (x = c) for all y.
	 	 * @return a vector (x,y) that is the intersection of two lines.
	 	 */
		public static function getLineCross(l1:Line, l2:Line):Point
		{
			if ( l1 == null || l2 == null ) 
			{
				return null ;
			}
			var a0:Number = l1.a ;
			var b0:Number = l1.b ;
			var c0:Number = l1.c ;
			var a1:Number = l2.a ;
			var b1:Number = l2.b ;
			var c1:Number = l2.c ;
			var u:Number ;
			if ( !c0 && !c1 ) 
			{
				if (a0 == a1) 
				{
					return null ;
				} 
				u = (b1 - b0) / (a0 - a1);		
				return new Point (u , a0 * u + b0 ) ;
			} 
			else 
			{
				if (c0) 
				{
					if (c1) 
					{	
						return null ;
					}
					else 
					{
						return new Point (c0, (a1*c0)+b1) ;
					}
				} 
				else if (c1) 
				{
					return new Point(c1, (a0*c1) + b0) ;
				}
				else
				{
					return null ;
				}
			}
		}
		
		/**
	 	 * Returns the middle of a segment define by two points.
	 	 * @return the middle of a segment define by two points.
	 	 */ 
		public static function getMiddle(v1:Point, v2:Point):Point 
		{
			return new Point( (v1.x + v2.x) / 2 , (v1.y + v2.y) / 2) ;
		}
		
		/**
		 * Returns a point on a segment [p1, p2] which distance from p1 is ratio of the length [p1, p2].
		 * @return a point on a segment [p1, p2] which distance from p1 is ratio of the length [p1, p2].
		 */
		public static function getPointOnSegment(p1:Point, p2:Point, ratio:Number):Point 
		{
			return new Point( p1.x + ((p2.x - p1.x) * ratio) , p1.y + ((p2.y - p1.y) * ratio) ) ;
		}	
		
		/**
	 	 * Returns a line equation as two properties (a,b) such that (y = a*x + b) for any x or a unique c property such that (x = c) for all y.
	 	 * The function takes two parameters, a point p(x,y) through which the line passes and a direction vector v(x,y).
	 	 * @return a line equation as two properties (a,b) such that (y = a*x + b) for any x.
	 	 */
		public static function getVectorLine(p:Point, v:Point):Line 
		{
			var l:Line = new Line() ;
			var x:Number = p.x;
			var vx:Number = v.x ;
			if (vx == 0) 
			{
				l.c = x ;
			}
			else 
			{
				l.a = v.y / vx ;
				l.b = p.y - (l.a * x);
			}
			return l ;
		}
	}
}
